/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo All rights
 * reserved.
 */
package ac.jp.u_tokyo.SyncLib.graphCombinator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import ac.jp.u_tokyo.SyncLib.Sync;
import ac.jp.u_tokyo.SyncLib.SyncFactory;
import ac.jp.u_tokyo.SyncLib.util.Pair;

public class GraphCombinatorFactory implements SyncFactory
{
	//	ForMap<String, Variable> _vars = new HashMap<String, Variable>();
	//	List<Variable> _paraVars = new ArrayList<Variable>();

	LinkedList<Pair<SyncFactory, String[]>> _syncConnections = new LinkedList<Pair<SyncFactory, String[]>>();

	LinkedList<String> _otherVars = new LinkedList<String>();

	LinkedList<String> _paraVars = new LinkedList<String>();

//	Object[] _initalValues;

	public void setParaVars(String... paras)
	{
		for (String v : paras)
		{
			_paraVars.add(v);
			//			Variable variable = new Variable();
			//			_vars.put(v, variable);
			//			_paraVars.add(variable);
		}
	}

	@Deprecated
	public void setInitialValues(Object... values)
	{
	}

	public void setOtherVars(String... vars)
	{
		for (String v : vars)
		{
			//			_vars.put(v, new Variable());
			_otherVars.add(v);
		}

	}

	public void connectSync(SyncFactory f, String... vars)
	{
		_syncConnections.add(new Pair(f, vars));
		//		assert s.getParaCount() == vars.length;
		//		SyncHolder sh = new SyncHolder(s);
		//		for(int i = 0; i < vars.length; i++) {
		//			assert _vars.containsKey(vars[i]);
		//			sh.connectVariable(i, _vars.get(vars[i]));
		//		}

	}

	public GraphCombinator create()
	{
//		assert _initalValues != null;
//		assert _initalValues.length == _paraVars.size();

		Map<String, Variable> vars = new HashMap<String, Variable>();
		Variable[] paraVars = new Variable[_paraVars.size()];
		SyncHolder[] syncHolders = new SyncHolder[_syncConnections.size()];
		for (String vname : _otherVars)
			vars.put(vname, new Variable());
		int i = 0;
		for (String vname : _paraVars)
		{
			Variable newV = new Variable();
			vars.put(vname, newV);
//			newV.setValue(_initalValues[i]);
			paraVars[i++] = newV;
		}
		int priority = _syncConnections.size();
		i = 0;
		for (Pair<SyncFactory, String[]> entry : _syncConnections)
		{
			Sync newSync = entry.getValue1().create();
			SyncHolder sh = new SyncHolder(newSync, priority--);
			String[] varsToConnect = entry.getValue2();
//			Object[] initialValues = sh.getSync().getInitialValues();
			for (int j = 0; j < varsToConnect.length; j++)
			{
				assert vars.containsKey(varsToConnect[j]) : varsToConnect[j];
				Variable var = vars.get(varsToConnect[j]);
				assert var != null;
				sh.connectVariable(j, var);
//				System.out.println("********************" + sh.getSync() + sh.getSync().hashCode() + ":" + initialValues[j]);
//				if (var.getValue() == null)
//					var.setValue(initialValues[j]);
//				else
//					assert var.getValue().equals(initialValues[j]) : "on var:"
//							+ var.getValue() + "\tnot on var:"
//							+ sh.getSync().getInitialValues()[j] + "\tvar:"
//							+ varsToConnect[j] + "\tSync:" + sh.getSync();
			}
			syncHolders[i++] = sh;
		}

		return new GraphCombinator(paraVars, syncHolders/*, _initalValues*/);
	}

}
